{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 基本的ResNet网络实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 导入相关包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "from torch import nn\n",
    "from torch.utils.data import DataLoader\n",
    "import torch.nn.functional as F\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import pickle\n",
    "import time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义预处理函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "if torch.cuda.is_available():\n",
    "    device=torch.device(\"cuda\")\n",
    "else:\n",
    "    device=torch.device(\"cpu\")\n",
    " \n",
    "mean = [0.5070751592371323, 0.48654887331495095, 0.4409178433670343]\n",
    "std = [0.2673342858792401, 0.2564384629170883, 0.27615047132568404]\n",
    " \n",
    "transforms_fn = torchvision.transforms.Compose([\n",
    "    torchvision.transforms.RandomHorizontalFlip(),  # 随机水平翻转\n",
    "    torchvision.transforms.RandomVerticalFlip(),  # 随机垂直翻转\n",
    "    torchvision.transforms.RandomRotation(10),  # 随机旋转\n",
    "    torchvision.transforms.ToTensor(),\n",
    "    torchvision.transforms.Normalize(mean, std)\n",
    "])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 导入CIFAR100"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Files already downloaded and verified\n",
      "Files already downloaded and verified\n"
     ]
    }
   ],
   "source": [
    "#100 classes containing 600 images each. There are 500 training images and 100 testing images per class.\n",
    "#训练集\n",
    "train_data=torchvision.datasets.CIFAR100('./data',train=True,transform=transforms_fn,download=True)\n",
    "#测试集\n",
    "test_data=torchvision.datasets.CIFAR100('./data',train=False,transform=transforms_fn,download=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ### 利用dataloader来加载数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "train= DataLoader(train_data, batch_size=128, shuffle=True, num_workers=4)\n",
    "test = DataLoader(test_data, batch_size=128, shuffle=True, num_workers=4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义残差块ResBlock"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ResBlock(nn.Module):\n",
    "    def __init__(self,inchannel,outchannel,stride=1):\n",
    "        super(ResBlock, self).__init__()\n",
    "        #定义残差块里连续的2个卷积层\n",
    "        self.block_conv=nn.Sequential(\n",
    "            nn.Conv2d(inchannel,outchannel,kernel_size=3,stride=stride,padding=1),\n",
    "            nn.BatchNorm2d(outchannel),\n",
    "            nn.ReLU(),\n",
    "            # nn.MaxPool2d(2),\n",
    "            nn.Conv2d(outchannel,outchannel,kernel_size=3,stride=1,padding=1),\n",
    "            nn.BatchNorm2d(outchannel)\n",
    "        )\n",
    " \n",
    "        # shortcut 部分\n",
    "        # 由于存在维度不一致的情况 所以分情况\n",
    "        self.shortcut = nn.Sequential()\n",
    "        if stride != 1 or inchannel != outchannel:\n",
    "            self.shortcut = nn.Sequential(\n",
    "                # 卷积核为1 进行升降维\n",
    "                # 注意跳变时 都是stride!=1的时候 也就是每次输出信道升维的时候\n",
    "                nn.Conv2d(inchannel, outchannel, kernel_size=1, stride=stride, bias=False),\n",
    "                nn.BatchNorm2d(outchannel)\n",
    "            )\n",
    " \n",
    "    def forward(self,x):\n",
    "        out1=self.block_conv(x)\n",
    "        out2=self.shortcut(x)+out1\n",
    "        out2=F.relu(out2) #F.relu()是函数调用，一般使用在foreward函数里。而nn.ReLU()是模块调用，一般在定义网络层的时候使用\n",
    "        return out2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 构建ResNet"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ResNet_18(nn.Module):\n",
    "    def __init__(self,ResBlock,num_classes):\n",
    "        super(ResNet_18, self).__init__()\n",
    " \n",
    "        self.in_channels = 64 #输入layer1时的channel\n",
    "        #第一层单独卷积层\n",
    "        self.conv1=nn.Sequential(\n",
    "            # (n-f+2*p)/s+1,n=28,n=32\n",
    "            # nn.Conv2d(in_channels=3,out_channels=64,kernel_size=7,stride=2,padding=3),\n",
    "            nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=1), #64\n",
    "            nn.BatchNorm2d(64),\n",
    "            nn.ReLU(),\n",
    "            # nn.MaxPool2d(kernel_size=3,stride=2,padding=1)\n",
    "            nn.MaxPool2d(kernel_size=1, stride=1, padding=0) #64\n",
    "            # nn.Dropout(0.25)\n",
    "        )\n",
    " \n",
    "        self.layer1=self.make_layer(ResBlock,64,2,stride=1) #64\n",
    "        self.layer2 = self.make_layer(ResBlock, 128, 2, stride=2) #32\n",
    "        self.layer3 = self.make_layer(ResBlock, 256, 2, stride=2) #16\n",
    "        self.layer4 = self.make_layer(ResBlock, 512, 2, stride=2) #8\n",
    " \n",
    " \n",
    "        self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) #torch.nn.AdaptiveAvgPool2d()接受两个参数，分别为输出特征图的长和宽，其通道数前后不发生变化。\n",
    "                                                    #即这里将输入图片像素强制转换为1*1\n",
    "        # self.linear=nn.Linear(2*2*512,512)\n",
    "        # self.linear2=nn.Linear(512,100)\n",
    " \n",
    "        self.linear=nn.Linear(512*1*1,num_classes)\n",
    " \n",
    "        self.dropout = nn.Dropout(0.3)\n",
    " \n",
    "    # 这个函数主要是用来，重复同一个残差块\n",
    "    def make_layer(self, block, out_channels, num_blocks, stride):\n",
    "        strides = [stride] + [1] * (num_blocks - 1)\n",
    "        layers = []\n",
    "        for stride in strides:\n",
    "            layers.append(block(self.in_channels, out_channels, stride))\n",
    "            self.in_channels = out_channels\n",
    "        return nn.Sequential(*layers)\n",
    " \n",
    "    def forward(self, x):\n",
    "        x=self.conv1(x)\n",
    "        # x=self.dropout(x)\n",
    "        x=self.layer1(x)\n",
    "        x = self.layer2(x)\n",
    "        x = self.layer3(x)\n",
    "        x = self.layer4(x)\n",
    "        x=self.avgpool(x)\n",
    "        x = x.view(x.size(0), -1)\n",
    "        x=self.linear(x)\n",
    "        x=self.dropout(x)\n",
    " \n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模型参数设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ResNet_18(\n",
      "  (conv1): Sequential(\n",
      "    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "    (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "    (2): ReLU()\n",
      "    (3): MaxPool2d(kernel_size=1, stride=1, padding=0, dilation=1, ceil_mode=False)\n",
      "  )\n",
      "  (layer1): Sequential(\n",
      "    (0): ResBlock(\n",
      "      (block_conv): Sequential(\n",
      "        (0): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "        (2): ReLU()\n",
      "        (3): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "      (shortcut): Sequential()\n",
      "    )\n",
      "    (1): ResBlock(\n",
      "      (block_conv): Sequential(\n",
      "        (0): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "        (2): ReLU()\n",
      "        (3): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "      (shortcut): Sequential()\n",
      "    )\n",
      "  )\n",
      "  (layer2): Sequential(\n",
      "    (0): ResBlock(\n",
      "      (block_conv): Sequential(\n",
      "        (0): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n",
      "        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "        (2): ReLU()\n",
      "        (3): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (4): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "      (shortcut): Sequential(\n",
      "        (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)\n",
      "        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "    )\n",
      "    (1): ResBlock(\n",
      "      (block_conv): Sequential(\n",
      "        (0): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "        (2): ReLU()\n",
      "        (3): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (4): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "      (shortcut): Sequential()\n",
      "    )\n",
      "  )\n",
      "  (layer3): Sequential(\n",
      "    (0): ResBlock(\n",
      "      (block_conv): Sequential(\n",
      "        (0): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n",
      "        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "        (2): ReLU()\n",
      "        (3): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "      (shortcut): Sequential(\n",
      "        (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)\n",
      "        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "    )\n",
      "    (1): ResBlock(\n",
      "      (block_conv): Sequential(\n",
      "        (0): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "        (2): ReLU()\n",
      "        (3): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "      (shortcut): Sequential()\n",
      "    )\n",
      "  )\n",
      "  (layer4): Sequential(\n",
      "    (0): ResBlock(\n",
      "      (block_conv): Sequential(\n",
      "        (0): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n",
      "        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "        (2): ReLU()\n",
      "        (3): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (4): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "      (shortcut): Sequential(\n",
      "        (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)\n",
      "        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "    )\n",
      "    (1): ResBlock(\n",
      "      (block_conv): Sequential(\n",
      "        (0): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "        (2): ReLU()\n",
      "        (3): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "        (4): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
      "      )\n",
      "      (shortcut): Sequential()\n",
      "    )\n",
      "  )\n",
      "  (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))\n",
      "  (linear): Linear(in_features=512, out_features=100, bias=True)\n",
      "  (dropout): Dropout(p=0.3, inplace=False)\n",
      ")\n"
     ]
    }
   ],
   "source": [
    "#网络模型\n",
    "model=ResNet_18(ResBlock,num_classes=100)\n",
    "model.to(device)\n",
    "print(model)\n",
    "#损失函数\n",
    "loss_fn=nn.CrossEntropyLoss() \n",
    "loss_fn.to(device)\n",
    " \n",
    "learning_rate=0.01\n",
    " \n",
    "optimizer=torch.optim.SGD(params=model.parameters(),lr=learning_rate, momentum=0.9,weight_decay=0.0001)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-----第1轮训练开始------\n",
      "Train loss:4.273622256670243   Train accuracy:6.864%   Test loss:3.951347589492798   Test accuracy:10.66%\n",
      "-----第2轮训练开始------\n",
      "Train loss:4.028283124703627   Train accuracy:10.668%   Test loss:3.7654515352004614   Test accuracy:13.99%\n",
      "-----第3轮训练开始------\n",
      "Train loss:3.8858934567524837   Train accuracy:13.062%   Test loss:3.602279929014353   Test accuracy:17.14%\n",
      "-----第4轮训练开始------\n",
      "Train loss:3.7659782495254124   Train accuracy:15.656%   Test loss:3.468284215682592   Test accuracy:19.31%\n",
      "-----第5轮训练开始------\n",
      "Train loss:3.66500374353849   Train accuracy:17.498%   Test loss:3.3291522356180043   Test accuracy:21.5%\n",
      "-----第6轮训练开始------\n",
      "Train loss:3.574286062900837   Train accuracy:19.178%   Test loss:3.2840769718854856   Test accuracy:22.88%\n",
      "-----第7轮训练开始------\n",
      "Train loss:3.4885162432988484   Train accuracy:21.274%   Test loss:3.153811974403186   Test accuracy:25.06%\n",
      "-----第8轮训练开始------\n",
      "Train loss:3.422908370311444   Train accuracy:22.248%   Test loss:3.0354942175058217   Test accuracy:27.38%\n",
      "-----第9轮训练开始------\n",
      "Train loss:3.348871122873746   Train accuracy:23.974%   Test loss:2.9755989404825063   Test accuracy:27.41%\n",
      "-----第10轮训练开始------\n",
      "Train loss:3.287995638602819   Train accuracy:25.028%   Test loss:2.866370133864574   Test accuracy:30.73%\n",
      "-----第11轮训练开始------\n",
      "Train loss:3.2391347090403237   Train accuracy:26.184%   Test loss:2.8337267484420385   Test accuracy:31.24%\n",
      "-----第12轮训练开始------\n",
      "Train loss:3.1945689623172466   Train accuracy:26.99%   Test loss:2.755471403782184   Test accuracy:32.8%\n",
      "-----第13轮训练开始------\n",
      "Train loss:3.165729056871854   Train accuracy:27.592%   Test loss:2.7509958346684775   Test accuracy:32.01%\n",
      "-----第14轮训练开始------\n",
      "Train loss:3.1170563141504926   Train accuracy:28.59%   Test loss:2.642906192021492   Test accuracy:34.48%\n",
      "-----第15轮训练开始------\n",
      "Train loss:3.072361297485156   Train accuracy:29.39%   Test loss:2.6773605346679688   Test accuracy:33.71%\n",
      "-----第16轮训练开始------\n",
      "Train loss:3.0388870080312094   Train accuracy:30.072%   Test loss:2.625618806252113   Test accuracy:35.74%\n",
      "-----第17轮训练开始------\n",
      "Train loss:3.0058686586526724   Train accuracy:30.922%   Test loss:2.5777354729481234   Test accuracy:36.12%\n",
      "-----第18轮训练开始------\n",
      "Train loss:2.9757820893556644   Train accuracy:31.738%   Test loss:2.5395705638787684   Test accuracy:37.47%\n",
      "-----第19轮训练开始------\n",
      "Train loss:2.9421566565831503   Train accuracy:32.54%   Test loss:2.4918180795816274   Test accuracy:39.3%\n",
      "-----第20轮训练开始------\n",
      "Train loss:2.9222699691087772   Train accuracy:32.852%   Test loss:2.448718841259296   Test accuracy:39.68%\n",
      "-----第21轮训练开始------\n",
      "Train loss:2.892209131901081   Train accuracy:33.314%   Test loss:2.420934729087047   Test accuracy:40.18%\n",
      "-----第22轮训练开始------\n",
      "Train loss:2.8723729475950583   Train accuracy:33.772%   Test loss:2.372060399789077   Test accuracy:41.08%\n",
      "-----第23轮训练开始------\n",
      "Train loss:2.845473685631385   Train accuracy:34.216%   Test loss:2.362383946394309   Test accuracy:41.42%\n",
      "-----第24轮训练开始------\n",
      "Train loss:2.833160092891791   Train accuracy:34.56%   Test loss:2.350999748095488   Test accuracy:42.01%\n",
      "-----第25轮训练开始------\n",
      "Train loss:2.80552937128605   Train accuracy:35.132%   Test loss:2.3400515975096288   Test accuracy:42.18%\n",
      "-----第26轮训练开始------\n",
      "Train loss:2.7853343755770954   Train accuracy:35.608%   Test loss:2.318583702429747   Test accuracy:42.27%\n",
      "-----第27轮训练开始------\n",
      "Train loss:2.7627167090391502   Train accuracy:36.176%   Test loss:2.304757764706245   Test accuracy:43.43%\n",
      "-----第28轮训练开始------\n",
      "Train loss:2.739612568341769   Train accuracy:36.468%   Test loss:2.276418609496875   Test accuracy:43.26%\n",
      "-----第29轮训练开始------\n",
      "Train loss:2.725629880489447   Train accuracy:36.806%   Test loss:2.2496337630809884   Test accuracy:43.99%\n",
      "-----第30轮训练开始------\n",
      "Train loss:2.705060994319427   Train accuracy:37.314%   Test loss:2.25509084493686   Test accuracy:43.47%\n",
      "-----第31轮训练开始------\n",
      "Train loss:2.685979047188392   Train accuracy:37.806%   Test loss:2.2068317104608584   Test accuracy:44.65%\n",
      "-----第32轮训练开始------\n",
      "Train loss:2.6823812851539026   Train accuracy:37.816%   Test loss:2.173801307494824   Test accuracy:45.66%\n",
      "-----第33轮训练开始------\n",
      "Train loss:2.650466959293072   Train accuracy:38.566%   Test loss:2.175679271037762   Test accuracy:45.61%\n",
      "-----第34轮训练开始------\n",
      "Train loss:2.643562013675005   Train accuracy:38.68%   Test loss:2.152418078520359   Test accuracy:46.43%\n",
      "-----第35轮训练开始------\n",
      "Train loss:2.622940833140642   Train accuracy:39.318%   Test loss:2.132382250749148   Test accuracy:45.73%\n",
      "-----第36轮训练开始------\n",
      "Train loss:2.6085279593100914   Train accuracy:39.58%   Test loss:2.1481796900431314   Test accuracy:46.25%\n",
      "-----第37轮训练开始------\n",
      "Train loss:2.61332844159542   Train accuracy:39.298%   Test loss:2.121126506573115   Test accuracy:46.51%\n",
      "-----第38轮训练开始------\n",
      "Train loss:2.591946128087166   Train accuracy:39.746%   Test loss:2.1162492709282117   Test accuracy:46.51%\n",
      "-----第39轮训练开始------\n",
      "Train loss:2.578590909639994   Train accuracy:39.798%   Test loss:2.0779260717905483   Test accuracy:47.79%\n",
      "-----第40轮训练开始------\n",
      "Train loss:2.570818139345218   Train accuracy:40.018%   Test loss:2.074123367285117   Test accuracy:47.72%\n",
      "-----第41轮训练开始------\n",
      "Train loss:2.539665894019298   Train accuracy:40.748%   Test loss:2.098329096268385   Test accuracy:46.96%\n",
      "-----第42轮训练开始------\n",
      "Train loss:2.527283166616391   Train accuracy:41.252%   Test loss:2.0400648896510782   Test accuracy:48.46%\n",
      "-----第43轮训练开始------\n",
      "Train loss:2.532773459263337   Train accuracy:41.174%   Test loss:2.075020437057202   Test accuracy:47.22%\n",
      "-----第44轮训练开始------\n",
      "Train loss:2.5116385435446715   Train accuracy:41.316%   Test loss:1.997297045512077   Test accuracy:49.7%\n",
      "-----第45轮训练开始------\n",
      "Train loss:2.5038831084202497   Train accuracy:41.618%   Test loss:2.0246462653844786   Test accuracy:49.08%\n",
      "-----第46轮训练开始------\n",
      "Train loss:2.4874780502074803   Train accuracy:41.9%   Test loss:1.9956443508466084   Test accuracy:49.08%\n",
      "-----第47轮训练开始------\n",
      "Train loss:2.474726507296929   Train accuracy:42.304%   Test loss:2.0597636500994363   Test accuracy:48.38%\n",
      "-----第48轮训练开始------\n",
      "Train loss:2.45713864839994   Train accuracy:42.612%   Test loss:2.0526401736797433   Test accuracy:47.43%\n",
      "-----第49轮训练开始------\n",
      "Train loss:2.45928003574029   Train accuracy:42.584%   Test loss:2.0067778122730746   Test accuracy:48.95%\n",
      "-----第50轮训练开始------\n",
      "Train loss:2.4485103640800867   Train accuracy:42.894%   Test loss:1.985826782691173   Test accuracy:49.52%\n"
     ]
    }
   ],
   "source": [
    "train_acc_list = []\n",
    "train_loss_list = []\n",
    "test_acc_list = []\n",
    "test_loss_list=[]\n",
    "epochs=200\n",
    " \n",
    "for epoch in range(epochs):\n",
    "    print(\"-----第{}轮训练开始------\".format(epoch + 1))\n",
    "    train_loss=0.0\n",
    "    test_loss=0.0\n",
    "    train_sum,train_cor,test_sum,test_cor=0,0,0,0\n",
    " \n",
    "    #训练步骤开始\n",
    "    model.train()\n",
    "    for batch_idx,(data,target) in enumerate(train):\n",
    "        data,target=data.to(device),target.to(device)\n",
    " \n",
    "        optimizer.zero_grad()  # 要将梯度清零，因为如果梯度不清零，pytorch中会将上次计算的梯度和本次计算的梯度累加\n",
    "        # output = model(data)\n",
    "        output = model(data)\n",
    "        # loss = loss_fn(output, target)\n",
    "        loss = loss_fn(output, target)\n",
    "        loss.backward()\n",
    "        optimizer.step()  # 更新所有的参数\n",
    " \n",
    "        # 计算每轮训练集的Loss\n",
    "        train_loss += loss.item()\n",
    " \n",
    "        _, predicted = torch.max(output.data, 1)  # 选择最大的（概率）值所在的列数就是他所对应的类别数，\n",
    "        # train_cor += (predicted == target).sum().item()  # 正确分类个数\n",
    "        train_cor += (predicted == target).sum().item()  # 正确分类个数\n",
    "        train_sum += target.size(0)  # train_sum+=predicted.shape[0]\n",
    " \n",
    "    #测试步骤开始\n",
    "    model.eval()\n",
    "    # with torch.no_grad():\n",
    "    for batch_idx1,(data,target) in enumerate(test):\n",
    "        data, target = data.to(device), target.to(device)\n",
    " \n",
    "        output = model(data)\n",
    "        loss = loss_fn(output, target)\n",
    "        test_loss+=loss.item()\n",
    "        _, predicted = torch.max(output.data, 1)\n",
    "        test_cor += (predicted == target).sum().item()\n",
    "        test_sum += target.size(0)\n",
    " \n",
    "    print(\"Train loss:{}   Train accuracy:{}%   Test loss:{}   Test accuracy:{}%\".format(train_loss/batch_idx,100*train_cor/train_sum,\n",
    "                                                                                       test_loss/batch_idx1,100*test_cor/test_sum))\n",
    "    train_loss_list.append(train_loss / batch_idx)\n",
    "    train_acc_list.append(100 * train_cor / train_sum)\n",
    "    test_acc_list.append(100 * test_cor/ test_sum)\n",
    "    test_loss_list.append(test_loss / batch_idx1)\n",
    " \n",
    "#保存网络\n",
    "torch.save(model,\"CIFAR100_epoch{}.pth\".format(epochs))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 读取模型并测试准确率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy of the network on the test images: 49 %\n"
     ]
    }
   ],
   "source": [
    "# 加载模型\n",
    "model = torch.load(\"CIFAR100_epoch50.pth\")\n",
    "model = model.to(device)\n",
    "\n",
    "# 测试步骤开始\n",
    "model.eval()\n",
    "correct = 0\n",
    "total = 0\n",
    "with torch.no_grad():\n",
    "    for data in test:\n",
    "        images, labels = data\n",
    "        images, labels = images.to(device), labels.to(device)\n",
    "        outputs = model(images)\n",
    "        _, predicted = torch.max(outputs.data, 1)\n",
    "        total += labels.size(0)\n",
    "        correct += (predicted == labels).sum().item()\n",
    "\n",
    "print('Accuracy of the network on the test images: %d %%' % (\n",
    "    100 * correct / total))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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1723iJRSsdth70KwOEHrR3Mec3aFpiOg/mBY+zGsmASndsN39+Wu7ODq0ON1qHr5v6N2lRpv9utZ+wlkJJv7gqqZCVe928C5aHxfFo0opEBVq1aN7777jl69emGxWHjhhReuWbOSH1988QVBQUEMHDjwsun5b775ZqZNm0b37t0ZN24cDzzwAKGhofTo0YPk5GRWrlzJQw89RPv27WnXrh39+/fn7bffJioqit27d2OxWOjevTsdOnTg1KlTvP766wwYMIBff/2VX3755boduitWrIibmxvvv/8+DzzwANu3b+ell17Kcc7o0aN5//33GTx4MM888wz+/v6sXr2a5s2b20Y+devWDT8/P15++WUmTJhg1+cnIiXMiknmz9p9IKjqlc9x84I2j0KTYWbC8Pev129iSj4Op/+GL/qYNTvdXgX/8vaL+6LzZ+GTTnA2xnwfWhvaPWF+HqeitRBukRq1JAXj7bffpkyZMrRq1YpevXrRrVs3GjdubNd7fPrpp/Tt2/eKawz179+f+fPnc/r0aYYOHco777zDlClTqFOnDj179mTv3r22c7/99luaNWvG7bffTu3atXnyySfJzjb/YteqVYspU6YwefJkGjRowNq1a3niiSeuG1tISAgzZsxgzpw51K5dm9dee40333wzxzlBQUEsWbKEc+fO0b59e5o0acInn3ySo3bGycmJYcOGkZ2dzd13353fRyUiJd2Z/bDjQn/ONo9d/3zPALOPyYMrYdTqa78e2QotHjBrenb+AB80gz/fgqx0+8VvtcK8B80kxq88DJoJD6yEuv2LXBIDYDHsOe63CEpKSsLf35/ExMTL/ueelpZmG1HjyEnbpPi45557OHXq1HXn1NHvlkgp9uMj5qieqK5w59yCuUfsdvj5CTh8YcmewKpmc1O1Lte+Ljf+fAsWTwBnd7hnIUQ0uvEy8+Fa39+XUo2MSC4kJiayYsUKZs2axUMPPeTocESkoBkGxCyHc6fydl3SCXMUEpidYQtKeF0Y/gv0/djsIBy/H2b2h9lD4Oyh/Jd7YBksedncvvkNhyUxeaFERiQXevfuzU033cQDDzyQY44eESmhVkyCz3rBh20g/kDur1s9GbIzoEJLqNSq4OIDsFigwSAYvR6iR4PFGXb/BJObm31u8trgknQc5o4AwwoNh0Dj4tGErkRGJBeWLl1Kamoq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OpQZM2bw5JNPkpKSwsiRI0lISKBNmzb8+uuveHgU3TWL1KwkIiJSeCyGYRiODqIgJSUl4e/vT2JiYoH3l8nIstLkpUUkp2fx3X9a0bhimQK9n4iISEmV2+/vIttHpjhafeAMyelZhPi607B8gKPDERERKfGUyNjRxWalLrVCcXKyODgaERGRkk+JjJ0YhsHvu9Q/RkREpDApkbGT7ceSOJGYhpebM62qapFIERGRwqBExk4W7TSXTWhXLQQPVy0SKSIiUhiUyNjJbxf7x6hZSUREpNAokbGDI/Gp7I5NxskCnbRIpIiISKFRImMHF0crNa0cSKC3m4OjERERKT2UyNjBxUTmJjUriYiIFColMjcoITWDtQfjAQ27FhERKWxKZG7QH3viyLYaVA/zoVKQFokUEREpTEpkbpAWiRQREXEcJTI3ID0rm2V7TgHQtXa4g6MREREpfZTI3IBV+8+QkpFNqK879cv5OzocERGRUkeJzA1YdMkkeFokUkREpPApkcknq1WLRIqIiDiaEpl82nYskZNJ6Xi7OdOqapCjwxERESmVlMjk08VmpfY1QnB30SKRIiIijqBEJp+S0jJxdbaoWUlERMSBLIZhGI4OoiAlJSXh7+9PYmIifn5+9i07LRNXJyc83VQjIyIiYk+5/f52KcSYShw/D1dHhyAiIlKqqWlJREREii0lMiIiIlJsKZERERGRYkuJjIiIiBRbSmRERESk2FIiIyIiIsWWEhkREREptpTIiIiISLGlREZERESKLSUyIiIiUmwpkREREZFiS4mMiIiIFFtKZERERKTYKvGrXxuGAZjLgYuIiEjxcPF7++L3+NWU+EQmOTkZgAoVKjg4EhEREcmr5ORk/P39r3rcYlwv1SnmrFYrx48fx9fXF4vFYrdyk5KSqFChAkeOHMHPz89u5cqV6XkXLj3vwqdnXrj0vAtXfp63YRgkJycTERGBk9PVe8KU+BoZJycnypcvX2Dl+/n56S9BIdLzLlx63oVPz7xw6XkXrrw+72vVxFykzr4iIiJSbCmRERERkWJLiUw+ubu7M3bsWNzd3R0dSqmg51249LwLn5554dLzLlwF+bxLfGdfERERKblUIyMiIiLFlhIZERERKbaUyIiIiEixpURGREREii0lMvk0efJkKleujIeHBy1atGDt2rWODqlEWL58Ob169SIiIgKL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MXLkSLZt28b8+fOJiorKcY/x48czcOBAtm7dys0338yQIUOIj48v1M8pInZww8tOiojkwdChQw1nZ2fD29s7x+uVV14xDMNckfuBBx7IcU2LFi2MBx980DAMw/j444+NMmXKGOfOnbMdX7BggeHk5GTExsYahmEYERERxnPPPXfVGADj+eeft70/d+6cARi//PKL3T6niBQO9ZERkULXsWNHpk6dmmNfYGCgbTs6OjrHsejoaDZv3gzArl27aNCgAd7e3rbjrVu3xmq1smfPHiwWC8ePH6dz587XjKF+/fq2bW9vb/z8/IiLi8vvRxIRB1EiIyKFztvb+7KmHnvx9PTM1Xmurq453lssFqxWa0GEJCIFSH1kRKTIWb169WXva9WqBUCtWrXYsmULKSkptuMrV67EycmJGjVq4OvrS+XKlVm8eHGhxiwijqEaGREpdOnp6cTGxubY5+LiQnBwMABz5syhadOmtGnThpkzZ7J27VqmTZsGwJAhQxg7dixDhw5l3LhxnDp1ioceeoi77rqLsLAwAMaNG8cDDzxAaGgoPXr0IDk5mZUrV/LQQw8V7gcVkQKnREZECt2vv/5K2bJlc+yrUaMGu3fvBswRRbNnz+Y///kPZcuW5auvvqJ27doAeHl5sXDhQh555BGaNWuGl5cX/fv35+2337aVNXToUNLS0pg0aRJPPPEEwcHBDBgwoPA+oIgUGothGIajgxARuchisTBv3jz69Onj6FBEpBhQHxkREREptpTIiIiISLGlPjIiUqSotVtE8kI1MiIiIlJsKZERERGRYkuJjIiIiBRbSmRERESk2FIiIyIiIsWWEhkREREptpTIiIiISLGlREZERESKLSUyIiIiUmz9PwcULMaAdIHgAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 创建一个新的图像\n",
    "plt.figure()\n",
    "\n",
    "# 绘制训练精度\n",
    "plt.plot(range(epochs), train_acc_list, label='Train Accuracy')\n",
    "\n",
    "# 绘制测试精度\n",
    "plt.plot(range(epochs), test_acc_list, label='Test Accuracy')\n",
    "\n",
    "# 添加图例\n",
    "plt.legend()\n",
    "\n",
    "# 添加标题和标签\n",
    "plt.title('Train and Test Accuracy')\n",
    "plt.xlabel('Epoch')\n",
    "plt.ylabel('Accuracy')\n",
    "\n",
    "# 显示图像\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
